<?php
/**
 * ModuleBase.class.php
 *
 * @author 周剑锋 <camfee@foxmail.com>
 * @date   17-9-1 下午5:32
 *
 */

namespace Common;

use lib\core\Module;

class ModuleBase extends Module
{
    /**
     * 基础配置文件
     *
     * @var array
     */
    protected static $_conf = [
        // 必选, 数据库代码 (来自Bridge配置), w: 写, r: 读
        'db' => [
            'w' => '',
            'r' => ''
        ],
        // 必选, 数据表名
        'table' => '',
        // 必选, 字段信息
        'fields' => [],
        // 可选, MC连接参数
        'mc' => '',
        // 可选, MC KEY, "KeyName:%d", %d会用主键ID替代
        'mckey' => '',
        // 可选, 超时时间, 默认不过期
        'mctime' => 0,
        // 可选, redis 链接
        'redis' => [
            'w' => '',
            'r' => '',
            'index' => 0
        ],
    ];

    // 列表缓存数组 [list_key{field} => [type => 1, fields => [field]]] 0:mc 1:redis 默认0
    const CACHE_LIST_TYPE = 'type';
    const CACHE_LIST_TYPE_MC = 0;
    const CACHE_LIST_TYPE_REDIS = 1;
    const CACHE_LIST_FIELDS = 'fields';
    const UPDATE_DEL_CACHE_LIST = false; // 更新是否清除列表缓存
    protected static $_cache_list_keys;
    const MC_LIST_DEMO_1 = 'MC_LIST_DEMO_1';
    const MC_LIST_DEMO_2 = 'MC_LIST_DEMO_2:{Id}';
    const MC_LIST_DEMO_3 = 'MC_LIST_DEMO_3:{Id}:{UserId}';
    private static $_cache_list_keys_demo = [
        self::MC_LIST_DEMO_1 => self::CACHE_LIST_TYPE_MC,
        self::MC_LIST_DEMO_2 => [
            self::CACHE_LIST_TYPE => self::CACHE_LIST_TYPE_MC,
            self::CACHE_LIST_FIELDS => 'Id',
        ],
        self::MC_LIST_DEMO_3 => [
            self::CACHE_LIST_TYPE => self::CACHE_LIST_TYPE_MC,
            self::CACHE_LIST_FIELDS => ['Id', 'UserId']
        ],
    ];
    // 新增必须字段 field => 1
    protected static $_add_must_fields;
    // 不可修改字段 field => 1
    protected static $_un_modify_fields = [
        'Id' => 1,
    ];

    /**
     * 获取列表
     *
     * @param $id
     * @return array
     */
    protected static function getDemoList($id)
    {
        $where = [
            'Id' => $id,
            'Status' => 1
        ];
        $extra = [
            'type' => parent::MOD_TYPE_MEMCACHE,
            'mckey' => self::MC_LIST_DEMO_2,
            'mtime' => 86400,
            'fields' => '*',
            'listkey' => 'Id',
            'listval' => '',
            'order' => '',
        ];

        return parent::getDataByFields($where, $extra);
    }

    /**
     * 获取Id列表
     * @param     $uid
     * @param int $offset
     * @param int $limit
     * @return array
     */
    protected static function getDemoIdList($uid, $offset = 0, $limit = 10)
    {
        $where = [
            'Id' => $uid,
            'Status' => 1
        ];
        $extra = [
            'type' => parent::MOD_TYPE_MEMCACHE,
            'mckey' => self::MC_LIST_DEMO_2,
            'mtime' => 86400,
            'order' => '',
        ];
        $data = parent::getDataByFields($where, $extra);

        if (!empty($data['data'])) {
            $data['data'] = array_slice($data['data'], $offset, $limit);
        }

        return $data;
    }

    /**
     * 新增
     *
     * @param      $data
     * @param bool $ignore
     * @return bool|int|string
     */
    public static function add($data, $ignore = false)
    {
        if (!empty(static::$_add_must_fields) && count(array_diff_key(static::$_add_must_fields, $data)) > 0) {
            return false;
        }
        $ret = false;
        if (!empty($data)) {
            if (!is_array($data[0]) && empty($data['CreateTime'])) {
                $data['CreateTime'] = date('Y-m-d H:i:s');
            }
            $ret = parent::addData($data, $ignore);
            if (!empty(static::$_cache_list_keys) && $ret !== false) {
                if (empty($data[key(static::$_conf['fields'])]) && !is_array($data[0])) {
                    $data[key(static::$_conf['fields'])] = $ret;
                } elseif(is_array($data[0])) {
                    $data = $data[0];
                }
                static::delListCache($data);
            }
        }

        return $ret;
    }

    /**
     * 更新
     *
     * @param $id
     * @param $data
     * @return bool
     */
    public static function update($id, $data)
    {
        $ret = false;
        if (!empty(static::$_un_modify_fields)) {
            $intersect_key = array_intersect_key($data, static::$_un_modify_fields);
            if (count($intersect_key) > 0) {
                return false;
            }
        }
        if ($id > 0 && !empty($data)) {
            $ret = parent::updateData($id, $data);
            if (!empty(static::$_cache_list_keys) && $ret !== false && !empty(static::UPDATE_DEL_CACHE_LIST)) {
                $info = static::getInfoByIds($id);
                if (!empty($info)) {
                    static::delListCache($info);
                }
            }
        }

        return $ret;
    }

    /**
     * 由主键获取全部信息
     *
     * @param $ids
     * @return array
     */
    public static function getInfoByIds($ids)
    {
        if (!empty($ids)) {
            $ret = parent::getDataById($ids);
        }

        return !empty($ret) ? $ret : [];
    }

    /**
     * 获取列表
     *
     * @param array  $where
     * @param int    $offset
     * @param int    $limit
     * @param string $field
     * @param string $order
     * @return array
     */
    public static function getList($where = [], $offset = 0, $limit = 10, $field = '*', $order = '')
    {
        $extra = [
            'offset' => $offset,
            'limit' => $limit,
            'fields' => $field,
            'order' => $order,
        ];

        return parent::getDataByFields($where, $extra);
    }

    /**
     * 删除
     *
     * @param $id
     * @return bool
     */
    public static function delete($id)
    {
        $ret = false;
        if (!empty($id)) {
            if (!empty(static::$_cache_list_keys)) {
                $info = static::getInfoByIds($id);
            }
            $ret = parent::delData($id);
            if ($ret !== false && !empty($info)) {
                static::delListCache($info);
            }
        }

        return $ret;
    }

    /**
     * 获取pdo实例
     *
     * @param bool $w
     * @return bool|\lib\plugins\pdo\PDOQuery|\PDOStatement
     */
    protected static function getPdo($w = false)
    {
        static $pdo_w, $pdo_r;
        if ($w) {
            if (empty($pdo_w)) {
                $pdo_w = Bridge::pdo(static::$_conf['db']['w']);
            }

            return $pdo_w;
        } else {
            if (empty($pdo_r)) {
                $pdo_r = Bridge::pdo(static::$_conf['db']['r']);
            }

            return $pdo_r;
        }
    }

    /**
     * 获取redis实例
     *
     * @param bool $w
     * @return \Redis
     */
    protected static function getRedis($w = false)
    {
        static $redis_w, $redis_r;
        if ($w) {
            if (empty($redis_w)) {
                $redis_w = Bridge::redis(static::$_conf['redis']['w'], static::$_conf['redis']['index']);
            }

            return $redis_w;
        } else {
            if (empty($redis_r)) {
                $redis_r = Bridge::redis(static::$_conf['redis']['r'], static::$_conf['redis']['index']);
            }

            return $redis_r;
        }
    }

    /**
     * 获取mc实例
     *
     * @param null $option
     * @return \lib\plugins\cache\Memcached
     */
    protected static function getMC($option = null)
    {
        static $mc;
        if (empty($mc)) {
            if (empty($option)) {
                $option = static::$_conf['mc'];
            }
            $mc = Bridge::memcache($option);
        }

        return $mc;
    }

    /**
     * 清除列表缓存
     *
     * @param array $info
     */
    protected static function delListCache($info = [])
    {
        if (!empty(static::$_cache_list_keys)) {
            $mc_key = $rd_key = [];
            foreach (static::$_cache_list_keys as $k => $v) {
                if (!is_array($v)) {
                    if ($v == static::CACHE_LIST_TYPE_REDIS) {
                        $rd_key[] = $k;
                    } else {
                        $mc_key[] = $k;
                    }
                } else {
                    if (empty($v[static::CACHE_LIST_FIELDS])) {
                        $key = $k;
                    } elseif (!is_array($v[static::CACHE_LIST_FIELDS])) {
                        $field = $v[static::CACHE_LIST_FIELDS];
                        $key = str_replace('{' . $field . '}', $info[$field], $k);
                    } else {
                        $search = $replace = [];
                        foreach ($v[static::CACHE_LIST_FIELDS] as $vv) {
                            $search[] = '{' . $vv . '}';
                            $replace[] = $info[$vv];
                        }
                        $key = str_replace($search, $replace, $k);
                    }
                    if (isset($v[static::CACHE_LIST_TYPE]) && $v[static::CACHE_LIST_TYPE] == static::CACHE_LIST_TYPE_REDIS) {
                        $rd_key[] = $key;
                    } else {
                        $mc_key[] = $key;
                    }
                }
            }
            if (!empty($mc_key)) {
                static::getMC()->delete($mc_key);
            }
            if (!empty($rd_key)) {
                static::getRedis(true)->delete($rd_key);
            }
        }
    }
}